﻿using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace CacheNaga
{
	/// <summary>
	/// PooledSocket类封装了到指定memcached server的socket链接.包含缓冲stream,发送和接受
	/// 数据的功能.
	/// </summary>
	internal class PooledSocket : IDisposable
	{
		private static LogAdapter logger = LogAdapter.GetLogger(typeof(PooledSocket));

		private SocketPool socketPool;
		private Socket socket;
		private Stream stream;
		/// <summary>
		/// socket的创建时间
		/// </summary>
		public readonly DateTime Created;

		public PooledSocket(SocketPool socketPool, IPEndPoint endPoint, int sendReceiveTimeout)
		{
			this.socketPool = socketPool;
			Created = DateTime.Now;
			//创建socket
			socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
			socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, sendReceiveTimeout);
			socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, sendReceiveTimeout);
			socket.ReceiveTimeout = sendReceiveTimeout;
			socket.SendTimeout = sendReceiveTimeout;
			//不发送小数据包
			socket.NoDelay = true;
			//连接
			socket.Connect(endPoint);
			//创建缓冲区
			stream = new BufferedStream(new NetworkStream(socket, false));
		}

		/// <summary>
		/// Disposing of a PooledSocket object in any way causes it to be returned to its SocketPool.
		/// </summary>
		public void Dispose()
		{
			socketPool.Return(this);
		}

		/// <summary>
		/// 关闭socket和相对应的stream
		/// </summary>
		public void Close()
		{
			if (stream != null)
			{
				try { stream.Close(); }
				catch (Exception e) { logger.Error("Error closing stream: " + socketPool.Host, e); }
				stream = null;
			}
			if (socket != null)
			{
				try { socket.Shutdown(SocketShutdown.Both); }
				catch (Exception e) { logger.Error("Error shutting down socket: " + socketPool.Host, e); }
				try { socket.Close(); }
				catch (Exception e) { logger.Error("Error closing socket: " + socketPool.Host, e); }
				socket = null;
			}
		}

		/// <summary>
		/// 看socket和stream是否可用
		/// </summary>
		public bool IsAlive
		{
			get { return socket != null && socket.Connected && stream.CanRead; }
		}

		/// <summary>
		/// 发送UTF-8编码的字节
		/// </summary>
		public void Write(string str)
		{
			Write(Encoding.UTF8.GetBytes(str));
		}

		/// <summary>
		/// 向服务器发送字节并flush stream
		/// </summary>
		public void Write(byte[] bytes)
		{
			stream.Write(bytes, 0, bytes.Length);
			stream.Flush();
		}

		/// <summary>
		/// 从socket读取内容直到\r\n
		/// 去除\r\n后返回utf-8编码的字符串
		/// </summary>
		public string ReadLine()
		{
			MemoryStream buffer = new MemoryStream();
			int b;
			bool gotReturn = false;
			while ((b = stream.ReadByte()) != -1/*NULL字符*/)
			{
				if (gotReturn)
				{
					if (b == 10)//如果是\n
					{
						break;
					}
					else
					{
						buffer.WriteByte(13);
						gotReturn = false;
					}
				}
				if (b == 13)//字符为\r
				{
					gotReturn = true;
				}
				else
				{
					//如果不是\r\n的话就写入缓冲
					buffer.WriteByte((byte)b);
				}
			}
			return Encoding.UTF8.GetString(buffer.GetBuffer());
		}

		/// <summary>
		/// 读取socket上的内容
		/// 如果没有内容或者返回的是memecahced的错误将抛出异常
		/// </summary>
		public string ReadResponse()
		{
			string response = ReadLine();

			if (String.IsNullOrEmpty(response))
			{
				throw new MemcachedClientException("无返回内容");
			}

			if (response.StartsWith("ERROR")
				|| response.StartsWith("CLIENT_ERROR")
				|| response.StartsWith("SERVER_ERROR"))
			{
				throw new MemcachedClientException("服务器返回 " + response);
			}

			return response;
		}

		/// <summary>
		/// 把socket的内容写入到bytes数组中
		/// </summary>
		public void Read(byte[] bytes)
		{
			if (bytes == null)
			{
				return;
			}

			int readBytes = 0;
			while (readBytes < bytes.Length)
			{
				readBytes += stream.Read(bytes, readBytes, (bytes.Length - readBytes));
			}
		}

		/// <summary>
		/// 读socket一直遇到\r\n为止
		/// </summary>
		public void SkipUntilEndOfLine()
		{
			int b;
			bool gotReturn = false;
			while ((b = stream.ReadByte()) != -1)
			{
				if (gotReturn)
				{
					if (b == 10)
					{
						break;
					}
					else
					{
						gotReturn = false;
					}
				}
				if (b == 13)
				{
					gotReturn = true;
				}
			}
		}

		/// <summary>
		/// 重设PooledSocket确保socket的写入缓冲是空的,如果不为空返回true
		/// </summary>
		public bool Reset()
		{
			//如果socket里还有已经接受的数据,那么返回true
			if (socket.Available > 0)
			{
				byte[] b = new byte[socket.Available];
				Read(b);
				return true;
			}
			return false;
		}
	}
}